package beefs.lowlevel;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.designwizard.design.ClassNode;
import org.designwizard.design.MethodNode;
import org.designwizard.exception.InexistentEntityException;
import org.designwizard.main.DesignWizard;
import org.junit.Test;

import beefs.common.Mappings;
import br.edu.ufcg.lsd.beefs.tools.Honeycomb;
import br.edu.ufcg.lsd.beefs.tools.Queenbee;

public class XSocketCommunicationTest {

	private DesignWizard dw;

	public XSocketCommunicationTest() {
		try {
			this.dw = new DesignWizard("resources/allclasses");
		} catch (IOException e) {}
	}


	@Test
	public void testBasicHandlerSubClasses() throws InexistentEntityException {
		System.out.println("---" + Mappings.XSOCKET_BASIC_HANDLER_CLASS  + " violations");

		ClassNode basicHandler = this.dw.getClass(Mappings.XSOCKET_BASIC_HANDLER_CLASS);

		// handlers são: basic, as subclasses e as classes internas
		Set<ClassNode> handlers = basicHandler.getSubClasses();
		handlers.addAll(basicHandler.getInnerClasses());
		handlers.add(basicHandler);

		Set<MethodNode> handlersMethods = new HashSet<MethodNode>();
		for (ClassNode handler : handlers)
			handlersMethods.addAll(handler.getAllMethods());

				boolean fail = false;

				for (MethodNode handlerMethod : handlersMethods) {

					Set<MethodNode> callerMethods = handlerMethod.getCallerMethods();
					for (MethodNode caller : callerMethods) {

						if (!caller.getName().startsWith((dw.getClass(Queenbee.class).getName())) &&
								!caller.getName().startsWith((dw.getClass(Honeycomb.class).getName())) &&
								!handlers.contains(caller.getClassNode())){
							fail = true;
							System.out.println(caller.getName() +" is_accessing " + handlerMethod.getName());
						}

					}

				}
		System.out.println();
		assertFalse(fail);

	}

	@Test
	public void testProtocolsSubClasses() throws InexistentEntityException {
		System.out.println("---" + Mappings.XSOCKET_PROTOCOL_CLASS + " violations");

		ClassNode protocol = this.dw.getClass(Mappings.XSOCKET_PROTOCOL_CLASS);
		Set<ClassNode> protocols = protocol.getSubClasses();
		protocols.add(protocol);

		boolean fail = false;

		Set<MethodNode> callee = new HashSet<MethodNode>();

		for (ClassNode c : protocols) {

			callee.addAll(c.getConstructors());

			try {
				MethodNode start = this.dw.getMethod(c.getName()+".startDaemon()");
				callee.add(start);
			} catch (InexistentEntityException e) {}

		}


		ClassNode protocolFactory = this.dw.getClass("br.edu.ufcg.lsd.beefs.communication.xsocket.spi.XSocketProtocolFactory");


		for (MethodNode m : callee) {

			Set<MethodNode> callerMethods = m.getCallerMethods();

			for (MethodNode caller : callerMethods)
				if (!caller.getClassNode().equals(protocolFactory)) {
					fail = true;
					System.out.println(caller.getName() +" is_accessing " + m.getName());
				}

		}
		System.out.println();
		assertFalse(fail);

	}



	@Test
	public void testXSocketCommunication() throws InexistentEntityException {
		System.out.println("---" + Mappings.XSOCKET_LIBRARY_ID + " violations");
		Set<MethodNode> allMethods = this.dw.getAllMethods();


		for (MethodNode caller : allMethods) {


			Set<MethodNode> calleeMethods = caller.getCalleeMethods();

			for (MethodNode callee : calleeMethods) {

				if (callee.getName().startsWith(Mappings.XSOCKET_LIBRARY_ID)) {

					assertTrue(caller.getName(),(caller.getName().startsWith(Mappings.XSOCKET_PROJECT_ID)
							|| caller.getName().startsWith(Mappings.XSOCKET_LIBRARY_ID)));


				}
			}

		}
		System.out.println();
	}

	@Test
	public void testHandlers() throws InexistentEntityException {
		System.out.println("---" + Mappings.XSOCKET_BASIC_HANDLER_CLASS + " violations");


		ClassNode basicHandler = this.dw.getClass(Mappings.XSOCKET_BASIC_HANDLER_CLASS);
		Set<ClassNode> handlers = basicHandler.getSubClasses();

		boolean fail = false;

		for (ClassNode handler : handlers) {

			// constructors and start constraints
			Set<MethodNode> constructors = handler.getConstructors();

			try {
				MethodNode start = this.dw.getMethod(handler.getName()+".startDaemon()");
				constructors.add(start);
			} catch (InexistentEntityException e) {}


			for (MethodNode constructor : constructors) {

				Set<MethodNode> callerMethods = constructor.getCallerMethods();
				for (MethodNode caller : callerMethods) {

					if (!caller.getName().endsWith("Handler") && !caller.getName().equals(Mappings.XSOCKET_PROTOCOL_FACTORY_CLASS)) {

						fail = true;
						System.out.println(caller.getName() +" is_accessing " + constructor.getName());

					}

				}


			}


		}
		System.out.println();
		assertFalse(fail);

	}

}